package com.ty.config;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import cn.smart.core.model.UserSession;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true,securedEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //责任链  + AOP
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable(); //禁用csrf
        http.sessionManagement().disable();//禁用session
        http.formLogin().disable();//禁用表单登录
        http.logout().disable();//禁用登出
        http.authorizeRequests()
                .antMatchers("/api/user/**").permitAll() //允许访问 /api/user/** 的所有请求
                .anyRequest().authenticated();//.anyRequest() 表示所有未被前面规则明确指定的请求。.authenticated() 指定这些请求需要经过身份验证才能访问。
        //在用户认证信息之前加一个过滤的节点
        http.addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

    }
    private class JwtAuthenticationFilter extends BasicAuthenticationFilter {

        public JwtAuthenticationFilter() throws Exception {
            super(authenticationManager());
        }
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
            // super.doFilterInternal(request, response, chain);
            String token = request.getHeader("token");
            if(ObjectUtil.isNotEmpty(token)){
                final JWT jwt = JWTUtil.parseToken(token);
                UserSession userSession = JSONUtil.toBean(jwt.getPayload().toString(), UserSession.class);
                List<GrantedAuthority> authorities = new ArrayList<>();
                List<String> roles = userSession.getRoles();
                roles.forEach(role -> {
                    authorities.add(new SimpleGrantedAuthority(role));
                });
                List<String> permissions = userSession.getPermissions();
                permissions.forEach(permission -> {
                    authorities.add(new SimpleGrantedAuthority(permission));
                });
                //把角色和权限添加到权限列表中
                UsernamePasswordAuthenticationToken toke = new UsernamePasswordAuthenticationToken(userSession.getId(), "",authorities);
                //把用户的这个我们自己设置的token 放到Security上下文
                SecurityContextHolder.getContext().setAuthentication(toke);
            }
            chain.doFilter(request, response);//请求接着往下走
        }
    }
}